/*****************************************************************************
 * Copyright (C) Stacy Curl. All rights reserved.                            *
 * ------------------------------------------------------------------------- *
 * The software in this package is published under the terms of the BSD      *
 * style license a copy of which has been included with this distribution in *
 * the LICENSE.txt file.                                                     *
 *****************************************************************************/
package picounit;

import picounit.mocker.ArrayConsequenceMatcher;
import picounit.mocker.BooleanArrayConsequenceMatcher;
import picounit.mocker.BooleanConsequenceMatcher;
import picounit.mocker.ByteArrayConsequenceMatcher;
import picounit.mocker.ByteConsequenceMatcher;
import picounit.mocker.CharArrayConsequenceMatcher;
import picounit.mocker.CharConsequenceMatcher;
import picounit.mocker.ConsequenceMatcher;
import picounit.mocker.DoubleArrayConsequenceMatcher;
import picounit.mocker.DoubleConsequenceMatcher;
import picounit.mocker.EventCapturer;
import picounit.mocker.FloatArrayConsequenceMatcher;
import picounit.mocker.FloatConsequenceMatcher;
import picounit.mocker.IntArrayConsequenceMatcher;
import picounit.mocker.IntConsequenceMatcher;
import picounit.mocker.ListConsequenceMatcher;
import picounit.mocker.LongArrayConsequenceMatcher;
import picounit.mocker.LongConsequenceMatcher;
import picounit.mocker.MockControl;
import picounit.mocker.MockFactory;
import picounit.mocker.OccurencesMatcher;
import picounit.mocker.PostConsequenceMatcher;
import picounit.mocker.SetConsequenceMatcher;
import picounit.mocker.ShortArrayConsequenceMatcher;
import picounit.mocker.ShortConsequenceMatcher;
import picounit.mocker.StringArrayConsequenceMatcher;
import picounit.mocker.StringConsequenceMatcher;
import picounit.mocker.VoidAction;
import picounit.verify.BooleanArrayConstraints;
import picounit.verify.BooleanConstraints;
import picounit.verify.ByteArrayConstraints;
import picounit.verify.ByteConstraints;
import picounit.verify.CharacterArrayConstraints;
import picounit.verify.CharacterConstraints;
import picounit.verify.CollectionConstraints;
import picounit.verify.DoubleArrayConstraints;
import picounit.verify.DoubleConstraints;
import picounit.verify.ExtendedStringConstraints;
import picounit.verify.FileConstraints;
import picounit.verify.FloatArrayConstraints;
import picounit.verify.FloatConstraints;
import picounit.verify.IntegerArrayConstraints;
import picounit.verify.IntegerConstraints;
import picounit.verify.ListConstraints;
import picounit.verify.LongArrayConstraints;
import picounit.verify.LongConstraints;
import picounit.verify.SetConstraints;
import picounit.verify.ShortArrayConstraints;
import picounit.verify.ShortConstraints;
import picounit.verify.StringArrayConstraints;
import picounit.verify.TypedArrayConstraints;
import picounit.verify.TypedConstraints;
import picounit.verify.VerifyStage;

import java.io.File;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import junit.framework.Assert;
import junit.framework.TestResult;

abstract public class TestCase implements Test {
	public final Is is;
	public final MockControl mockControl;
	public final MockFactory mockFactory;
	public final Should should;
	public final Verify verify;
	
	public TestCase() {
		this.isSetter = ControlledDelegate.createSetter();
		this.mockControlSetter = ControlledDelegate.createSetter();
		this.mockFactorySetter = ControlledDelegate.createSetter();
		this.shouldSetter = ControlledDelegate.createSetter();
		this.verifySetter = ControlledDelegate.createSetter();

		this.is = new DelegateIs(isSetter);
		this.mockControl = new DelegateMockControl(mockControlSetter);
		this.mockFactory = new DelegateMockFactory(mockFactorySetter);
		this.should = new DelegateShould(shouldSetter);
		this.verify = new DelegateVerify(verifySetter);
	}

	public final void setUp(Is is, MockControl mockControl, MockFactory mockFactory, Should should,
		Verify verify) {

		this.isSetter.setDelegate(is);
		this.mockControlSetter.setDelegate(mockControl);
		this.mockFactorySetter.setDelegate(mockFactory);
		this.shouldSetter.setDelegate(should);
		this.verifySetter.setDelegate(verify);
	}

	/** setUp methods need to have public visibility in PicoUnit */
	public void setUp() throws Exception {
	}

	/** tearDown methods need to have public visibility in PicoUnit */
	public void tearDown() throws Exception {
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// JUnit equivalent methods 
	///////////////////////////////////////////////////////////////////////////////////////////////

	public void assertTrue(boolean expression) {
		verify.that(expression).isTrue();
	}
	
	public void assertTrue(String message, boolean expression) {
		verify.because(message)
			.that(expression).isTrue();
	}

	public void assertFalse(boolean expression) {
		verify.that(expression).isFalse();
	}
	
	public void assertFalse(String message, boolean expression) {
		verify.because(message)
			.that(expression).isFalse();
	}
	
	public void assertEquals(boolean expected, boolean actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(String message, boolean expected, boolean actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}

	public void assertEquals(byte expected, byte actual) {
		verify.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(String message, byte expected, byte actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}

	public void assertEquals(char expected, char actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(String message, char expected, char actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(double expected, double actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(String message, double expected, double actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(float expected, float actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(String message, float expected, float actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(int expected, int actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(String message, int expected, int actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(long expected, long actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(String message, long expected, long actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(short expected, short actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(String message, short expected, short actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(Object expected, Object actual) {
		verify.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(String message, Object expected, Object actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(String expected, String actual) {
		verify.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(String message, String expected, String actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertNotNull(Object object) {
		verify.that(object).isNotNull();
	}
	
	public void assertNotNull(String message, Object object) {
		verify.because(message)
			.that(object).isNotNull();
	}
	
	public void assertNull(Object object) {
		verify.that(object).isNull();
	}
	
	public void assertNull(String message, Object object) {
		verify.because(message)
			.that(object).isNull();
	}
	
	public void assertSame(Object expected, Object actual) {
		verify.that(actual).isTheSameAs(expected);
	}
	
	public void assertSame(String message, Object expected, Object actual) {
		verify.because(message)
			.that(actual).isTheSameAs(expected);
	}
	
	public void assertNotSame(Object notExpected, Object actual) {
		verify.that(actual).isNotTheSameAs(notExpected);
	}

	public void assertNotSame(String message, Object notExpected, Object actual) {
		verify.because(message)
			.that(actual).isNotTheSameAs(notExpected);
	}
	
	public void fail() {
		verify.fail();
	}

	public void fail(String message) {
		verify.fail(message);
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	// Additional Methods
	///////////////////////////////////////////////////////////////////////////////////////////////

	public void assertEquals(boolean expected, Boolean actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(Boolean expected, boolean actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(String message, boolean expected, Boolean actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(String message, Boolean expected, boolean actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(byte expected, Byte actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(Byte expected, byte actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(String message, byte expected, Byte actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(String message, Byte expected, byte actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(char expected, Character actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(Character expected, char actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(String message, char expected, Character actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(String message, Character expected, char actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(Float expected, float actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(float expected, Float actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(String message, float expected, Float actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(String message, Float expected, float actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(double expected, Double actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(Double expected, double actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(String message, double expected, Double actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}

	public void assertEquals(String message, Double expected, double actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}

	public void assertEquals(int expected, Integer actual) {
		verify.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(Integer expected, int actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(String message, int expected, Integer actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(String message, Integer expected, int actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}

	public void assertEquals(long expected, Long actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(Long expected, long actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(String message, long expected, Long actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(String message, Long expected, long actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(short expected, Short actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(Short expected, short actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(String message, short expected, Short actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}

	public void assertEquals(String message, Short expected, short actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}

	public void assertEquals(double[] expected, double[] actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(String message, double[] expected, double[] actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(float[] expected, float[] actual) {
		verify.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(String message, float[] expected, float[] actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(long[] expected, long[] actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(String message, long[] expected, long[] actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(boolean[] expected, boolean[] actual) {
		verify.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(String message, boolean[] expected, boolean[] actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(byte[] expected, byte[] actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(String message, byte[] expected, byte[] actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(char[] expected, char[] actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(String message, char[] expected, char[] actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(int[] expected, int[] actual) {
		verify.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(String message, int[] expected, int[] actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(short[] expected, short[] actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(String message, short[] expected, short[] actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}

	public void assertEquals(Object[] expected, Object[] actual) {
		verify.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(String message, Object[] expected, Object[] actual) {
		verify.because(message)
		.that(actual).isEqualTo(expected);
	}
	
	public void assertEquals(String[] expected, String[] actual) {
		verify.that(actual).isEqualTo(expected);
	}

	public void assertEquals(String message, String[] expected, String[] actual) {
		verify.because(message)
			.that(actual).isEqualTo(expected);
	}

	public void assertNotEquals(boolean expected, boolean actual) {
		verify.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(String message, boolean expected, boolean actual) {
		verify.because(message)
		.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(byte expected, byte actual) {
		verify.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(String message, byte expected, byte actual) {
		verify.because(message)
		.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(char expected, char actual) {
		verify.that(actual).isDifferentTo(expected);
	}

	public void assertNotEquals(String message, char expected, char actual) {
		verify.because(message)
			.that(actual).isDifferentTo(expected);
	}

	public void assertNotEquals(double expected, double actual) {
		verify.that(actual).isDifferentTo(expected);
	}

	public void assertNotEquals(String message, double expected, double actual) {
		verify.because(message)
		.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(float expected, float actual) {
		verify.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(String message, float expected, float actual) {
		verify.because(message)
			.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(int expected, int actual) {
		verify.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(String message, int expected, int actual) {
		verify.because(message)
		.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(long expected, long actual) {
		verify.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(String message, long expected, long actual) {
		verify.because(message)
			.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(short expected, short actual) {
		verify.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(String message, short expected, short actual) {
		verify.because(message)
			.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(Object expected, Object actual) {
		verify.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(String message, Object expected, Object actual) {
		verify.because(message)
		.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(String expected, String actual) {
		verify.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(String message, String expected, String actual) {
		verify.because(message)
		.that(actual).isDifferentTo(expected);
	}

	public void assertNotEquals(boolean[] expected, boolean[] actual) {
		verify.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(String message, boolean[] expected, boolean[] actual) {
		verify.because(message)
			.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(byte[] expected, byte[] actual) {
		verify.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(String message, byte[] expected, byte[] actual) {
		verify.because(message)
		.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(char[] expected, char[] actual) {
		verify.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(String message, char[] expected, char[] actual) {
		verify.because(message)
			.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(double[] expected, double[] actual) {
		verify.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(String message, double[] expected, double[] actual) {
		verify.because(message)
			.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(float[] expected, float[] actual) {
		verify.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(String message, float[] expected, float[] actual) {
		verify.because(message)
			.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(long[] expected, long[] actual) {
		verify.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(String message, long[] expected, long[] actual) {
		verify.because(message)
			.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(int[] expected, int[] actual) {
		verify.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(String message, int[] expected, int[] actual) {
		verify.because(message)
			.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(short[] expected, short[] actual) {
		verify.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(String message, short[] expected, short[] actual) {
		verify.because(message)
			.that(actual).isDifferentTo(expected);
	}

	public void assertNotEquals(Object[] expected, Object[] actual) {
		verify.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(String message, Object[] expected, Object[] actual) {
		verify.because(message)
			.that(actual).isDifferentTo(expected);
	}

	public void assertNotEquals(String[] expected, String[] actual) {
		verify.that(actual).isDifferentTo(expected);
	}
	
	public void assertNotEquals(String message, String[] expected, String[] actual) {
		verify.because(message)
			.that(actual).isDifferentTo(expected);
	}

	public <B, D extends B> void assertInstanceOf(String message, Class<D> instanceOf, B object) {
		verify.because(message)
			.that(object).isAnInstanceOf(instanceOf);
	}

	public <B, D extends B> void assertInstanceOf(Class<D> instanceOf, B object) {
		verify.that(object).isAnInstanceOf(instanceOf);
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// Collaboration methods
	///////////////////////////////////////////////////////////////////////////////////////////////

	public EventCapturer expectTo(String reason) {
		return should.expectTo(reason);
	}

	public void expectAboveWhenTheFollowingOccurs() {
		should.expectAboveWhenTheFollowingOccurs();
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	// Injection methods
	///////////////////////////////////////////////////////////////////////////////////////////////

    public <T> T injectCollaborator() {
    	return Injector.injectCollaborator(getClass());
    }

    public <T> T injectFixture() {
        return Injector.injectFixture();
    }
    
    ///////////////////////////////////////////////////////////////////////////////////////////////
	// Occurence methods
	///////////////////////////////////////////////////////////////////////////////////////////////
    
    public Occurences once() {
    	return between(1, 1);
    }
    
    public Occurences atLeastOnce() {
    	return between(1, Integer.MAX_VALUE);
    }
    
    public Occurences optionally() {
    	return between(0, Integer.MAX_VALUE);
    }
    
    public Occurences between(int min, int max) {
    	return new OccurenceRange(min, max);
    }

    @SuppressWarnings("unused")
	private int countTestCases() {
		return 0;
	}

	@SuppressWarnings("unused")
	private TestResult createResult() {
		return null;
	}

	@SuppressWarnings("unused")
	private TestResult run() {
		return null;
	}

	@SuppressWarnings("unused")
	private void run(TestResult result) {
	}

	@SuppressWarnings("unused")
	private void runBare() throws Throwable {
	}

	@SuppressWarnings("unused")
	private void runTest() throws Throwable {
	}

	@SuppressWarnings("unused")
	private String getName() {
		return null;
	}

	@SuppressWarnings("unused")
	private void setName(String name) {
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// Implementation
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	private final ControlledDelegate.Setter<Should> shouldSetter;
	private final ControlledDelegate.Setter<Is> isSetter;
	private final ControlledDelegate.Setter<MockControl> mockControlSetter;
	private final ControlledDelegate.Setter<MockFactory> mockFactorySetter;
	private final ControlledDelegate.Setter<Verify> verifySetter;

	public static abstract class ControlledDelegate<Delegate> {
		private Delegate delegate;

		public static <Delegate> Setter<Delegate> createSetter() {
			return new Setter<Delegate>();
		}

		public ControlledDelegate(Setter<Delegate> setter) {
			setter.setPassThrough(new PassThrough<Delegate>() {
				public void setDelegate(Delegate delegate) {
					ControlledDelegate.this.delegate = delegate;
				}
			});
		}

		protected final Delegate delegate() {
			return delegate;
		}

		public static final class Setter<Delegate> {
			private PassThrough<Delegate> passThrough;

			public void setDelegate(Delegate delegate) {
				passThrough.setDelegate(delegate);
			}

			public void setPassThrough(PassThrough<Delegate> passThrough) {
				this.passThrough = passThrough;
			}
		}

		private interface PassThrough<Delegate> {
			void setDelegate(Delegate delegate);
		}
	}

	private final static class DelegateShould extends ControlledDelegate<Should> implements Should {
		public DelegateShould(Setter<Should> setter) {
			super(setter);
		}

		public EventCapturer expectTo(String reason) {
			return delegate().expectTo(reason);
		}

		public BooleanConsequenceMatcher call(boolean ignore) {
			return delegate().call(ignore);
		}

		public BooleanArrayConsequenceMatcher call(boolean[] ignore) {
			return delegate().call(ignore);
		}

		public ByteConsequenceMatcher call(byte ignore) {
			return delegate().call(ignore);
		}

		public ByteArrayConsequenceMatcher call(byte[] ignore) {
			return delegate().call(ignore);
		}

		public CharConsequenceMatcher call(char ignore) {
			return delegate().call(ignore);
		}

		public CharArrayConsequenceMatcher call(char[] ignore) {
			return delegate().call(ignore);
		}

		public DoubleConsequenceMatcher call(double ignore) {
			return delegate().call(ignore);
		}

		public DoubleArrayConsequenceMatcher call(double[] ignore) {
			return delegate().call(ignore);
		}

		public FloatConsequenceMatcher call(float ignore) {
			return delegate().call(ignore);
		}

		public FloatArrayConsequenceMatcher call(float[] ignore) {
			return delegate().call(ignore);
		}

		public IntConsequenceMatcher call(int ignore) {
			return delegate().call(ignore);
		}

		public IntArrayConsequenceMatcher call(int[] ignore) {
			return delegate().call(ignore);
		}

		public <T> ListConsequenceMatcher<T> call(List<T> ignore) {
			return delegate().call(ignore);
		}

		public LongConsequenceMatcher call(long ignore) {
			return delegate().call(ignore);
		}

		public LongArrayConsequenceMatcher call(long[] ignore) {
			return delegate().call(ignore);
		}

		public <T> SetConsequenceMatcher<T> call(Set<T> ignore) {
			return delegate().call(ignore);
		}

		public ShortConsequenceMatcher call(short ignore) {
			return delegate().call(ignore);
		}

		public ShortArrayConsequenceMatcher call(short[] ignore) {
			return delegate().call(ignore);
		}

		public StringConsequenceMatcher call(String ignore) {
			return delegate().call(ignore);
		}

		public StringArrayConsequenceMatcher call(String[] ignore) {
			return delegate().call(ignore);
		}

		public <T> ConsequenceMatcher<T> call(T ignore) {
			return delegate().call(ignore);
		}

		public <T> ArrayConsequenceMatcher<T> call(T[] ignore) {
			return delegate().call(ignore);
		}

		public void expectAboveWhenTheFollowingOccurs() {
			delegate().expectAboveWhenTheFollowingOccurs();
		}
		
		public void thenExpect() {
			delegate().thenExpect();
		}

		public PostConsequenceMatcher notCall(boolean ignore) {
			return delegate().notCall(ignore);
		}

		public PostConsequenceMatcher notCall(byte ignore) {
			return delegate().notCall(ignore);
		}

		public PostConsequenceMatcher notCall(char ignore) {
			return delegate().notCall(ignore);
		}

		public PostConsequenceMatcher notCall(double ignore) {
			return delegate().notCall(ignore);
		}

		public PostConsequenceMatcher notCall(float ignore) {
			return delegate().notCall(ignore);
		}

		public PostConsequenceMatcher notCall(int ignore) {
			return delegate().notCall(ignore);
		}

		public PostConsequenceMatcher notCall(long ignore) {
			return delegate().notCall(ignore);
		}

		public PostConsequenceMatcher notCall(short ignore) {
			return delegate().notCall(ignore);
		}

		public PostConsequenceMatcher notCall(String ignore) {
			return delegate().notCall(ignore);
		}

		public <T> PostConsequenceMatcher notCall(T ignore) {
			return delegate().notCall(ignore);
		}

		public OccurencesMatcher perform(VoidAction voidAction) {
			return delegate().perform(voidAction);
		}

		public OccurencesMatcher raise(Throwable throwable) {
			return delegate().raise(throwable);
		}
	}

	private final static class DelegateIs extends ControlledDelegate<Is> implements Is {
		public DelegateIs(Setter<Is> setter) {
			super(setter);
		}

		public double aDouble() {
			return delegate().aDouble();
		}

		public double almostEqualTo(double equalTo, double errorAllowed) {
			return delegate().almostEqualTo(equalTo, errorAllowed);
		}

		public int almostEqualTo(int equalTo, int errorAllowed) {
			return delegate().almostEqualTo(equalTo, errorAllowed);
		}

		public long almostEqualTo(long equalTo, long errorAllowed) {
			return delegate().almostEqualTo(equalTo, errorAllowed);
		}

		public long aLong() {
			return delegate().aLong();
		}

		public int anInteger() {
			return delegate().anInteger();
		}

		public Object anObject() {
			return delegate().anObject();
		}

		public Object aNullObject() {
			return delegate().aNullObject();
		}

		public String aNullString() {
			return delegate().aNullString();
		}

		public String aString() {
			return delegate().aString();
		}

		public String aStringContaining(String toContain) {
			return delegate().aStringContaining(toContain);
		}

		public String aStringMatching(String pattern) {
			return delegate().aStringMatching(pattern);
		}

		public String aStringNotContaining(String notToContain) {
			return delegate().aStringNotContaining(notToContain);
		}

		public String aStringNotMatching(String pattern) {
			return delegate().aStringNotMatching(pattern);
		}

		public double between(double lowerLimit, double upperLimit) {
			return delegate().between(lowerLimit, upperLimit);
		}

		public int between(int lowerLimit, int upperLimit) {
			return delegate().between(lowerLimit, upperLimit);
		}

		public long between(long lowerLimit, long upperLimit) {
			return delegate().between(lowerLimit, upperLimit);
		}

		public String equalToIgnoringCase(String toEqual) {
			return delegate().equalToIgnoringCase(toEqual);
		}

		public <T> Future<T> future(Class<T> futureType) {
			return delegate().future(futureType);
		}

		public double greaterThan(double lowerLimit) {
			return delegate().greaterThan(lowerLimit);
		}

		public int greaterThan(int lowerLimit) {
			return delegate().greaterThan(lowerLimit);
		}

		public long greaterThan(long lowerLimit) {
			return delegate().greaterThan(lowerLimit);
		}

		public double greaterThanOrEqualTo(double lowerLimit) {
			return delegate().greaterThanOrEqualTo(lowerLimit);
		}

		public int greaterThanOrEqualTo(int lowerLimit) {
			return delegate().greaterThanOrEqualTo(lowerLimit);
		}

		public long greaterThanOrEqualTo(long lowerLimit) {
			return delegate().greaterThanOrEqualTo(lowerLimit);
		}

		public <T> T instanceOf(Class<T> instanceOf) {
			return delegate().instanceOf(instanceOf);
		}

		public double lessThan(double upperLimit) {
			return delegate().lessThan(upperLimit);
		}

		public int lessThan(int upperLimit) {
			return delegate().lessThan(upperLimit);
		}

		public long lessThan(long upperLimit) {
			return delegate().lessThan(upperLimit);
		}

		public double lessThanOrEqualTo(double upperLimit) {
			return delegate().lessThanOrEqualTo(upperLimit);
		}

		public int lessThanOrEqualTo(int upperLimit) {
			return delegate().lessThanOrEqualTo(upperLimit);
		}

		public long lessThanOrEqualTo(long upperLimit) {
			return delegate().lessThanOrEqualTo(upperLimit);
		}

		public double neitherOf(double... neitherOf) {
			return delegate().neitherOf(neitherOf);
		}

		public int neitherOf(int... neitherOf) {
			return delegate().neitherOf(neitherOf);
		}

		public long neitherOf(long... neitherOf) {
			return delegate().neitherOf(neitherOf);
		}

		public Object neitherOf(Object... neitherOf) {
			return delegate().neitherOf(neitherOf);
		}

		public String neitherOf(String... neitherOf) {
			return delegate().neitherOf(neitherOf);
		}

		public Object notANullObject() {
			return delegate().notANullObject();
		}

		public String notANullString() {
			return delegate().notANullString();
		}

		public double notBetween(double lowerLimit, double upperLimit) {
			return delegate().notBetween(lowerLimit, upperLimit);
		}

		public int notBetween(int lowerLimit, int upperLimit) {
			return delegate().notBetween(lowerLimit, upperLimit);
		}

		public long notBetween(long lowerLimit, long upperLimit) {
			return delegate().notBetween(lowerLimit, upperLimit);
		}

		public Object notEqual(Object notEqual) {
			return delegate().notEqual(notEqual);
		}

		public double notEqualTo(double notEqual) {
			return delegate().notEqualTo(notEqual);
		}

		public int notEqualTo(int notEqual) {
			return delegate().notEqualTo(notEqual);
		}

		public long notEqualTo(long notEqual) {
			return delegate().notEqualTo(notEqual);
		}

		public String notEqualTo(String notEqual) {
			return delegate().notEqualTo(notEqual);
		}

		public double oneOf(double... oneOf) {
			return delegate().oneOf(oneOf);
		}

		public int oneOf(int... oneOf) {
			return delegate().oneOf(oneOf);
		}

		public long oneOf(long... oneOf) {
			return delegate().oneOf(oneOf);
		}

		public Object oneOf(Object... oneOf) {
			return delegate().oneOf(oneOf);
		}

		public String oneOf(String... oneOf) {
			return delegate().oneOf(oneOf);
		}
		
		public byte[] aByteArray() {
			return delegate().aByteArray();
		}
	}
	
	private final static class DelegateMockControl extends ControlledDelegate<MockControl>
		implements MockControl {

		public DelegateMockControl(Setter<MockControl> setter) {
			super(setter);
		}

		public void expectAboveWhenTheFollowingOccurs() {
			delegate().expectAboveWhenTheFollowingOccurs();
		}

		public void record() {
			delegate().record();
		}

		public void record(Object mock) {
			delegate().record(mock);
		}

		public void reset() {
			delegate().reset();
		}

		public void verify() {
			delegate().verify();
		}
	}
	
	private final static class DelegateMockFactory extends ControlledDelegate<MockFactory>
		implements MockFactory {

		public DelegateMockFactory(Setter<MockFactory> setter) {
			super(setter);
		}

		public <T> T mock(Class<T> interfaceClass, String name) {
			return delegate().mock(interfaceClass, name);
		}

		public <T> T mock(Class<T> interfaceClass) {
			return delegate().mock(interfaceClass);
		}

		public <T> T stub(Class<T> stubClass, Object implementation, String name) {
			return delegate().stub(stubClass, implementation, name);
		}

		public <T> T stub(Class<T> stubClass, Object implementation) {
			return delegate().stub(stubClass, implementation);
		}
	}
	
	private final static class DelegateVerify extends ControlledDelegate<Verify> implements Verify {
		public DelegateVerify(Setter<Verify> setter) {
			super(setter);
		}

		public VerifyStage because(String reason) {
			return delegate().because(reason);
		}
		
		public void fail() {
			delegate().fail();
		}

		public void fail(String message) {
			delegate().fail(message);
		}

		public BooleanArrayConstraints that(boolean... value) {
			return delegate().that(value);
		}

		public BooleanConstraints that(boolean value) {
			return delegate().that(value);
		}
		
		public BooleanConstraints that(Boolean value) {
			return delegate().that(value);
		}
		
		public BooleanArrayConstraints that(Boolean... value) {
			return delegate().that(value);
		}

		public ByteArrayConstraints that(byte... value) {
			return delegate().that(value);
		}

		public ByteConstraints that(byte value) {
			return delegate().that(value);
		}
		
		public ByteConstraints that(Byte value) {
			return delegate().that(value);
		}
		
		public ByteArrayConstraints that(Byte... value) {
			return delegate().that(value);
		}

		public CharacterArrayConstraints that(char... value) {
			return delegate().that(value);
		}

		public CharacterConstraints that(char value) {
			return delegate().that(value);
		}
		
		public CharacterConstraints that(Character value) {
			return delegate().that(value);
		}
		
		public CharacterArrayConstraints that(Character... value) {
			return delegate().that(value);
		}

		public DoubleArrayConstraints that(double... value) {
			return delegate().that(value);
		}

		public DoubleConstraints that(double value) {
			return delegate().that(value);
		}
		
		public DoubleConstraints that(Double value) {
			return delegate().that(value);
		}
		
		public DoubleArrayConstraints that(Double... value) {
			return delegate().that(value);
		}

		public FloatArrayConstraints that(float... value) {
			return delegate().that(value);
		}

		public FloatConstraints that(float value) {
			return delegate().that(value);
		}
		
		public FloatConstraints that(Float value) {
			return delegate().that(value);
		}
		
		public FloatArrayConstraints that(Float... value) {
			return delegate().that(value);
		}

		public IntegerArrayConstraints that(int... value) {
			return delegate().that(value);
		}

		public IntegerConstraints that(int value) {
			return delegate().that(value);
		}
		
		public IntegerConstraints that(Integer value) {
			return delegate().that(value);
		}
		
		public IntegerArrayConstraints that(Integer... value) {
			return delegate().that(value);
		}

		public LongArrayConstraints that(long... value) {
			return delegate().that(value);
		}

		public LongConstraints that(long value) {
			return delegate().that(value);
		}
		
		public LongConstraints that(Long value) {
			return delegate().that(value);
		}
		
		public LongArrayConstraints that(Long... value) {
			return delegate().that(value);
		}

		public ShortArrayConstraints that(short... value) {
			return delegate().that(value);
		}

		public ShortConstraints that(short value) {
			return delegate().that(value);
		}
		
		public ShortConstraints that(Short value) {
			return delegate().that(value);
		}

		public ShortArrayConstraints that(Short... value) {
			return delegate().that(value);
		}

		public StringArrayConstraints that(String... value) {
			return delegate().that(value);
		}

		public ExtendedStringConstraints that(String value) {
			return delegate().that(value);
		}

		public <T> TypedArrayConstraints<T> that(T... value) {
			return delegate().that(value);
		}

		public <T> TypedConstraints<T> that(T value) {
			return delegate().that(value);
		}

		public <T> CollectionConstraints<T> that(Collection<T> value) {
			return delegate().that(value);
		}
		
		public <T> ListConstraints<T> that(List<T> value) {
			return delegate().that(value);
		}

		public <T> SetConstraints<T> that(Set<T> value) {
			return delegate().that(value);
		}

		public FileConstraints that(File value) {
			return delegate().that(value);
		}
	}
	
	private class OccurenceRange implements Occurences {
		private final int min;
		private final int max;

		public OccurenceRange(int min, int max) {
			this.min = min;
			this.max = max;
		}

		public boolean matchesAnotherInvocation() {
			return true;
		}

		public void verify(int occurences) {
			Assert.assertTrue(occurences >= min);
			Assert.assertTrue(occurences <= max);
		}
	}
}
